#include "Race.h"
using namespace std;

DebugLevelType Race::elementaire  = BLANK;
DebugLevelType Race::fonction     = BLANK;

/**
 * Constructeur standard.
 * @param type nom de la race
 */
Race::Race(const string& type)
{
  Type = type;
  ptrCapa    = 0;
  ptrNbrCapa = 0;
  ptrEns     = 0;
  ptrNbrEns  = 0;
  ptrMaxEns  = 0;
}

/**
 * Constructeur de copie, réalise une copie profonde.
 * @param race race à copier
 */
Race::Race(const Race& race)
{
  unsigned int taille(race.capacites.size());
  for (unsigned int i(0); i<taille; i++)
    capacites.push_back(race.capacites[i]);
  Type = race.Type;
  ptrCapa    = race.ptrCapa;
  ptrNbrCapa = race.ptrNbrCapa;
  ptrEns     = race.ptrEns;
  ptrNbrEns  = race.ptrNbrEns;
  ptrMaxEns  = race.ptrMaxEns;
}

/**
 * Destructeur, ne fait rien de spécial.
 */
Race::~Race()
{}

/**
 * Méthode qui n'applique auqun ajustement, pour les races sans ajustement
 * @param tab tableau contenant les 6 traits
 */
void Race::appliquer_ajustements(unsigned int tab[6])
{}

/**
 * Affiche les capacités raciales.
 * \e FUNC permet d'afficher le nom de la méthode en début et fin d'exécution
 * \e LFUNC permet d'afficher de numéro de chaque capacité
 * \e DEBUG permet d'afficher le nombre de capacités
 * @param os flot, par défaut blank() est utilisé
 */
void Race::affiche_info(ostream& os) const
{
  DebugLevelType etat_precedent(dout.getLevel());
  dout.setLevel(fonction);
  func() << "Race::affiche_info -> début" << endreq;

  os << "Race : " << Type << endreq;

  unsigned int taille( get_taille() );

  debug() << "Nbr de capacités " << taille << endreq;

  for (unsigned int i(0); i < taille; i++)
    {
      lfunc() << i << "-ème capacité " << get_capa(i) << endreq;
      os << get_capacite(i) << endreq;
    }


  func() << "Race::affiche_info -> fin" << endreq;
  dout.setLevel(etat_precedent);
}

/**
 * Retourne la race (càd le nom).
 * @return le nom de la race
 */
string Race::get_Type() const
{
  return Type;
}

/**
 * Retourne le nombre de capacités raciales.
 * @return la dimension du conteneur capacites.
 */
unsigned int Race::get_taille() const
{
  return capacites.size();
}

/**
 * Retourne la capacité désirée.
 * \e FUNC permet d'afficher le nom de la méthode en début et fin d'exécution
 * @param i le numéro de la capacité
 * @return la position de la capacité dans la liste
 */
unsigned int Race::get_capa(const unsigned int& i) const
{
  DebugLevelType etat_precedent(dout.getLevel());
  dout.setLevel(elementaire);
  func() << "Race::get_capa -> début" << endreq;

  if (i < capacites.size())
    {
      func() << "Race::get_capa -> fin" << endreq;
      dout.setLevel(etat_precedent);
      return capacites[i];
    }
  else
    {
      error() << "Compétence inexistante, dépassement de portée" << endreq;
      func() << "Race::get_capa -> fin" << endreq;
      dout.setLevel(etat_precedent);
      return 65535;
    }
}

/**
 * Retrouve la capacité raciale désirée.
 * \e FUNC permet d'afficher le nom de la méthode en début et fin d'exécution
 * @param i numéro de la capacité
 * @return la capacité (string)
 */
string Race::get_capacite(const unsigned int& i) const
{
  DebugLevelType etat_precedent(dout.getLevel());
  dout.setLevel(elementaire);
  func() << "Race::get_capacite -> début" << endreq;

  if (i >= *ptrNbrCapa)
    {
      warning() << "Tentative d'accéder à une capacité inconnue" << endreq;
      func() << "Race::get_capacite -> fin" << endreq;
      dout.setLevel(etat_precedent);
      return "";
    }
  else
    {
      func() << "Race::get_capacite -> fin" << endreq;
      dout.setLevel(etat_precedent);
      return ptrCapa -> at(i) . Capa;
    }
}

void Race::get_capacites(unsigned int& nbr, vector<ListCapa>& capa) const
{
  DebugLevelType etat_precedent(dout.getLevel());
  dout.setLevel(elementaire);
  func() << "Race::get_capacites -> début" << endreq;
  
  nbr = *ptrNbrCapa;

  capa.assign( ptrCapa -> begin(), ptrCapa -> end() );

  func() << "Race::get_capacites -> fin" << endreq;
  dout.setLevel(etat_precedent);
}

void Race::get_ensemble_racial(unsigned int& nbr, unsigned int& max) const
{
  nbr = *ptrNbrEns;
  max = *ptrMaxEns;
}

const vector<unsigned int>* Race::get_ensemble_racial(const unsigned int& nbr) const
{
  if (nbr >= *ptrNbrEns)
    {
      warning() << "Tentative d'accéder à un ensembe racial non existant" 
		<< endreq;
      return 0;
    }
  return & (ptrEns -> at(nbr)); 
}


unsigned int Race::get_PP() const
{
  if (Type == "Humain")
    return 10;
  else if (Type == "Demi-Elfe")
    return 25;
  else if (Type == "Demi-Ogre")
    return 15;
  else if (Type == "Demi-Orque")
    return 15;
  else if (Type == "Elfe")
    return 45;
  else if (Type == "Gnome")
    return 45;
  else if (Type == "Hobbit")
    return 35;
  else if (Type == "Nain")
    return 45;
  else
    return 0;
}

void Race::set_capacites(const vector<unsigned int>& capa)
{
  unsigned int i, nbr(capa.size());

  capacites.clear();

  for (i = 0; i < nbr; i++)
    {
      capacites.push_back(capa[i]);
    }
}

/**
 * Gestion des niveau de sortie des fonctions.
 * @param level le niveau (INFO, DEBUG, ...).
 * @param n permet de sélectionner quel variable est affectée.
 * @see DebugLevelType
 */
void Race::setLevel(const DebugLevelType& level, const unsigned int& n)
{
  switch(n)
    {
    case 1:
      elementaire = level;
      break;
    case 2:
      fonction = level;
      break;
    default:
      warning() << "Variable inconnue, dans Race::setLevel " << n << endreq;
    }
}

/**
 * Retrouve les capacités raciales. Les numéros de ces capacités
 * sont retournées.
 * @param vec le conteneur où seront stockés les numéros
 */
void Race::get_toutes_capacites(vector<unsigned int>& vec) const
{
  vec.assign(capacites.begin(), capacites.end());
}
